import 'package:async/async.dart';
import 'package:boss/color_constant.dart';
import 'package:boss/main.dart';
import 'package:boss/models/sort_commodity_cell.dart';
import 'package:boss/models/store_revenue.dart';
import 'package:boss/models/store_staff_data.dart';
import 'package:boss/ui/widget/calendar/calendar.dart';
import 'package:boss/ui/widget/calendar/util/date_util.dart';
import 'package:boss/ui/widget/calendar_bar.dart';
import 'package:boss/ui/widget/charts/bar/bar_chart.dart';
import 'package:boss/ui/widget/charts/pie/pie_chart.dart';
import 'package:boss/ui/widget/charts/util/charts_color_util.dart';
import 'package:boss/ui/widget/loading/loading.dart';
import 'package:boss/ui/widget/picker/commodityPicker/commodity_picker.dart';
import 'package:flustars/flustars.dart' as flustars;
import 'package:flutter/material.dart';
import 'package:hi_common/hi_common.dart';

class AnalysisProvider extends ChangeNotifier {
  int timerSelectedIndex = 0;

  int tabSelectedIndex = 0;

  int commoditySelectedType = 1;

  int takeOutSelectedType = 1;

  int countSelectedType = 1;

  DateTime startTime = DateUtils.startOfTheDay(DateTime.now());

  DateTime endTime = DateUtils.endOfTheDay(DateTime.now());

  String get revenueDateText {
    if (timerSelectedIndex == 0) {
      return '较前一日';
    } else if (timerSelectedIndex == 1) {
      return '较前一周';
    } else if (timerSelectedIndex == 2) {
      return '较前一月';
    } else {
      final days = endTime.difference(startTime).inDays + 1;
      return '较前$days日';
    }
  }

  String get httpStartTimeText {
    return flustars.DateUtil.formatDate(startTime);
  }

  String get httpEndTimeText {
    return flustars.DateUtil.formatDate(endTime);
  }

  String get timerRangeText {
    return '${flustars.DateUtil.formatDate(startTime, format: flustars.DateFormats.y_mo_d_h_m)}至${flustars.DateUtil.formatDate(endTime, format: flustars.DateFormats.y_mo_d_h_m)}';
  }

  StoreRevenue storeRevenue;

  int moneyType = 0;

  int moneyIndex = 0;

  List<PieData<int>> get moneyData {
    if (moneyType == 0) {
      return [
        PieData<int>(
          '自取',
          storeRevenue.selfFoodMoney,
          ColorConstant.fc031,
        ),
        PieData<int>(
          '外卖',
          storeRevenue.takeOutFoodMoney,
          ColorConstant.fbd43,
        ),
        PieData<int>(
          '堂食',
          storeRevenue.foodMoney,
          ColorConstant.ff5770f6,
        ),
      ];
    } else {
      return [
        PieData<int>(
          '自取',
          storeRevenue.selfNum,
          ColorConstant.fc031,
        ),
        PieData<int>(
          '外卖',
          storeRevenue.takeOutFoodNum,
          ColorConstant.fbd43,
        ),
        PieData<int>(
          '堂食',
          storeRevenue.foodNum,
          ColorConstant.ff5770f6,
        ),
      ];
    }
  }

  int orderType = 0;

  int orderIndex = 0;

  List<PieData<int>> get orderData {
    if (orderType == 1) {
      return [
        PieData<int>(
          '收银机',
          storeRevenue.cashierByNum,
          ColorConstant.fe337d,
        ),
        PieData<int>(
          '服务员',
          storeRevenue.waiterByNum,
          ColorConstant.ff5770f6,
        ),
        PieData<int>(
          '扫码点餐',
          storeRevenue.qrCodeByNum,
          ColorConstant.fc031,
        ),
        PieData<int>(
          '外卖',
          storeRevenue.selfByNum,
          ColorConstant.f645cff,
        ),
      ];
    } else {
      return [
        PieData<int>(
          '收银机',
          storeRevenue.cashierByMoney,
          ColorConstant.fe337d,
        ),
        PieData<int>(
          '服务员',
          storeRevenue.waiterByMoney,
          ColorConstant.ff5770f6,
        ),
        PieData<int>(
          '扫码点餐',
          storeRevenue.qrCodeByMoney,
          ColorConstant.fc031,
        ),
        PieData<int>(
          '外卖',
          storeRevenue.selfByMoney,
          ColorConstant.f645cff,
        ),
      ];
    }
  }

  int payIndex = 0;

  List<PieData<int>> get payData {
    return storeRevenue.payTypesList
        .map((item) => PieData<int>(
              item.payTypeName,
              item.totalFee,
              ChartsColorUtil.getColorIndex(storeRevenue.payTypesList.indexOf(item)),
            ))
        .toList();
  }

  List<SortCommodityCell> commoditys;

  StoreStaffData staffData;

  List<BarData<double>> get storeSellSort {
    return staffData.saleListSort.map((item) {
      return BarData<double>(
        item.waiterName ?? '其他',
        item.totalFee / 100,
        ChartsColorUtil.getColorIndex(staffData.saleListSort.indexOf(item)),
      );
    }).toList();
  }

  List<BarData<double>> get tipSort {
    return staffData.tipListSort.map((item) {
      return BarData<double>(
        item.waiterName ?? '其他',
        item.tip / 100,
        ChartsColorUtil.getColorIndex(staffData.tipListSort.indexOf(item)),
      );
    }).toList();
  }

  List<BarData<int>> get customerSort {
    return staffData.staffCustomList.map((item) {
      return BarData<int>(
        item.waiterName ?? '其他',
        item.count,
        ChartsColorUtil.getColorIndex(staffData.staffCustomList.indexOf(item)),
      );
    }).toList();
  }

  List<BarData<double>> get takeoutSort {
    return staffData.takeOutListSort.map((item) {
      return BarData<double>(
        item.waiterName ?? '其他',
        item.totalFee / 100,
        ChartsColorUtil.getColorIndex(staffData.takeOutListSort.indexOf(item)),
      );
    }).toList();
  }

  List<BarData<double>> get commodityCommissionSort {
    return staffData.staffRoyaltyList.map((item) {
      return BarData<double>(
        item.waiterName,
        item.amount / 100,
        ChartsColorUtil.getColorIndex(staffData.staffRoyaltyList.indexOf(item)),
      );
    }).toList();
  }

  List<BarData<int>> get bookListSort {
    return staffData.bookListSort.map((item) {
      return BarData<int>(
        item.waiterName,
        item.bookTableNum,
        ChartsColorUtil.getColorIndex(staffData.bookListSort.indexOf(item)),
      );
    }).toList();
  }

  List<BarData<int>> get commentListSort {
    return staffData.commentList.map((item) {
      return BarData<int>(
        item.waiterName,
        int.parse(item.highRate),
        ChartsColorUtil.getColorIndex(staffData.commentList.indexOf(item)),
      );
    }).toList();
  }

  List<BarData<double>> get staffCommissionList {
    return staffData.staffCommissionList.map((item) {
      return BarData<double>(
        item.waiterName,
        item.amount / 100,
        ChartsColorUtil.getColorIndex(staffData.staffCommissionList.indexOf(item)),
      );
    }).toList();
  }

  List<BarData<double>> get couponIncomeRankList {
    return staffData.couponIncomeRank.map((item) {
      return BarData<double>(
        item.waiterName,
        item.amount / 100,
        ChartsColorUtil.getColorIndex(staffData.couponIncomeRank.indexOf(item)),
      );
    }).toList();
  }

  setMoneyType(int type) {
    moneyType = type;
    notifyListeners();
  }

  setOrderType(int type) {
    orderType = type;
    notifyListeners();
  }

  setCommodityType(int value) async {
    commoditySelectedType = value;
    notifyListeners();

    showLoadingToast();
    await querySortCommodityCells();
    hideLoadingToast();
  }

  setCountType(int value) async {
    countSelectedType = value;
    notifyListeners();

    showLoadingToast();
    await querySortCommodityCells();
    hideLoadingToast();
  }

  setTimerRange(int index) async {
    timerSelectedIndex = index;

    bool isRefresh = true;

    if (index == 0) {
      startTime = DateUtils.startOfTheDay(DateTime.now());
      endTime = DateUtils.endOfTheDay(DateTime.now());
    } else if (index == 1) {
      startTime = DateUtils.startOfTheWeek(DateTime.now());
      endTime = DateUtils.endOfTheWeek(DateTime.now());
    } else if (index == 2) {
      startTime = DateUtils.startOfTheMonth(DateTime.now());
      endTime = DateUtils.endOfTheMonth(DateTime.now());
    } else {
      var res = await openCalendarPicker(
        GlobalPageContext.instance.context,
        startDateTime: startTime,
        endDateTime: endTime,
        type: CalendarType.ymdhm,
      );
      if (res != null) {
        startTime = res[0];
        endTime = res[1];
      } else {
        isRefresh = false;
      }
    }
    notifyListeners();

    if (isRefresh) {
      refreshTab(tabSelectedIndex);
    }
  }

  setTakeOutType(int value) async {
    takeOutSelectedType = value;
    notifyListeners();

    showLoadingToast();
    await querySortCommodityCells();
    hideLoadingToast();
  }

  Future<Result<List>> queryStoreRevenue() async {
    try {
      var res = await api.queryStoreRevenueForTime(
        startTime: httpStartTimeText,
        endTime: httpEndTimeText,
      );
      if (!res.successful()) {
        return Result.error(res.msg);
      }

      storeRevenue = res.data;
      notifyListeners();

      return Result.value([]);
    } catch (e) {
      return Result.error(e.toString());
    }
  }

  Future<Result<List<SortCommodityCell>>> querySortCommodityCells() async {
    try {
      var res = await api.queryAndSortCommodityForTime(
        startTime: httpStartTimeText,
        endTime: httpEndTimeText,
        commodityOrMenu: commoditySelectedType,
        takeOutType: takeOutSelectedType,
        sortType: countSelectedType,
      );
      if (!res.successful()) {
        return Result.error(res.msg);
      }

      commoditys = res.data;
      notifyListeners();

      return Result.value(res.data);
    } catch (e) {
      return Result.error(e.toString());
    }
  }

  Future<Result<List>> queryStaff() async {
    try {
      var res = await api.queryStoreStaffForTime(
        startTime: httpStartTimeText,
        endTime: httpEndTimeText,
      );
      if (!res.successful()) {
        return Result.error(res.msg);
      }

      staffData = res.data;
      notifyListeners();

      return Result.value([]);
    } catch (e) {
      return Result.error(e.toString());
    }
  }

  changeTabIndex(int index) {
    tabSelectedIndex = index;

    refreshTab(index);
  }

  refreshTab(int index) async {
    if ((index == 0 && storeRevenue == null) || (index == 1 && staffData == null) || (index == 2 && commoditys == null)) return;

    Map<int, Function> refreshMap = {
      0: queryStoreRevenue,
      1: queryStaff,
      2: querySortCommodityCells,
    };

    await refreshMap[index]();
  }

  AnalysisProvider() {
    refreshTab(0);
  }

  setMoneyIndex(int index) {
    moneyIndex = index;
    notifyListeners();
  }

  setOrderIndex(int index) {
    orderIndex = index;
    notifyListeners();
  }

  setPayIndex(int index) {
    payIndex = index;
    notifyListeners();
  }
}
